#include <windows.h>

#include "Utils/CWindowClass.h"

#include "Utils/listKeyClass.h"
#include "Utils/T2List.h"
#include "Utils/T2AvlList.h"
#include "Utils/T2DLinkedList.h"
#include "CSemaphore.h"
#include "CConsole.h"

#ifdef UNICODE
#define WINDOWCLASSNAME L"AxiumWindowClass"
#define WINDOWTITLE L"Unnamed window"
#else
#define WINDOWCLASSNAME "AxiumWindowClass"
#define WINDOWTITLE "Unnamed window"
#endif

CWindowClass::CWindowClass()
{
	#ifdef WIN32
	//CConsole::outDebOnly("Creating window (Addr: %d)",this);
	m_pValueList = new T3ListProtected<CStringKeyCI,sProfileEntry*,T2AVLList>();
	m_pNewEntryQueue = new T3ListProtected<CStringKeyCI,sProfileEntry*,T2DLinkedList>();

	this->registerWindowClass(NULL);

	CreateThread(0,0,CWindowClass::handleWindow,this,0,0);

	Sleep(100);

	if (handleWindow == NULL)
		CConsole::outErr("Creation of window failed! (Addr: %d)",this);
	#endif

	m_visible = true;
}

CWindowClass::~CWindowClass()
{

}

DWORD WINAPI CWindowClass::handleWindow(LPVOID lpParam)
{
	#ifdef WIN32
	CWindowClass* window = (CWindowClass*)lpParam;

	HWND newWindowHandle;

	newWindowHandle = CreateWindow(
	   WINDOWCLASSNAME, // Predefined class
	   WINDOWTITLE, // Caption.
	   WS_OVERLAPPEDWINDOW, // Styles. 
	   CW_USEDEFAULT,	// x position. 
	   0,	// y position. 
	   325,	// width.
	   200,	// height.
	   NULL, 
	   NULL, 
	   NULL, 
	   NULL);

	if (newWindowHandle==NULL)
	{
		CConsole::outDebOnly("Creation of profile window failed! CreateWindow did not return a valid handle!");
		return 0; 
	}

	ShowWindow(newWindowHandle, SW_SHOW);
	UpdateWindow(newWindowHandle);
	RedrawWindow(newWindowHandle, NULL, NULL, RDW_INVALIDATE);
	MSG msg;

	window->setWindowHandle(newWindowHandle);

	int y = 0;
	int dy = 16;

	sProfileEntry* newEntry;

	char newText[MAXKEYSIZE + MAXKEYSIZE + 10];

	while (GetMessage(&msg, newWindowHandle, 0, 0))
	{
		while (window->m_pNewEntryQueue->getSize()>0)
		{
			newEntry = window->m_pNewEntryQueue->getFirst();
			window->m_pNewEntryQueue->removeAt(0);

			sprintf(newText,"%s: %s",newEntry->m_CaptionText,newEntry->m_ValueText);

			newEntry->m_Label = CreateWindowA( 
				"STATIC",   // Predefined class; Unicode assumed. 
				newText,       // Button text. 
				WS_TABSTOP | WS_VISIBLE | WS_CHILD | WS_BORDER |  SS_LEFT,  // Styles. 
				0,         // x position. 
				y,         // y position. 
				1050,        // width.
				17,        // height.
				newWindowHandle,       // Parent window.
				NULL,       // No menu.
				(HINSTANCE)GetWindowLong(newWindowHandle, GWL_HINSTANCE), 
				NULL);      // Pointer not needed.

			y+=dy;
		}
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	#endif

	return 1;
}

ATOM CWindowClass::registerWindowClass(HINSTANCE hInstance)
{
	ATOM retVal = 0;

	#ifdef WIN32
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
	wcex.lpfnWndProc	= CWindowClass::callbackProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= NULL;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW);
	wcex.lpszMenuName	= NULL; 
	wcex.lpszClassName	= WINDOWCLASSNAME;
	wcex.hIconSm		= NULL;

	retVal = RegisterClassEx(&wcex);
	#endif

	return retVal;
}

sProfileEntry* CWindowClass::getEntry(char* key)
{
	return this->m_pValueList->find(CStringKeyCI(key));
}

void CWindowClass::addEntry(char* key, sProfileEntry* entry)
{
	this->m_pValueList->pushBack(CStringKeyCI(key),entry);
}

void CWindowClass::setValue(char* key, int newValue)
{
	char newValueString[1000];
	sprintf(newValueString,"%d",newValue);
	setValueString(key,newValueString);
}

void CWindowClass::setValue(char* key, char* format ,... )
{
	va_list ap;
	char newValue[1024];

	va_start(ap, format);		// Parses The String For Variables
		vsprintf(newValue, format, ap);	// And Converts Symbols To Actual Numbers
	va_end(ap);

	setValueString(key,newValue);
}

void CWindowClass::setValueString(char* key, char* newValue)
{
	#ifdef WIN32
	sProfileEntry* entry = this->getEntry(key);
	if (entry == NULL)
	{
		entry = new sProfileEntry();

		if (strlen(key)>MAXKEYSIZE)
		{
			memcpy(entry->m_CaptionText,key,MAXKEYSIZE);
			entry->m_CaptionText[MAXKEYSIZE] = '\0';
			CConsole::outDebOnly("CProfilingWindow: Truncated caption for value '%s' to '%s'!",key,entry->m_CaptionText); 
		}
		else
		{
			strcpy(entry->m_CaptionText,key);
		}

		if (strlen(newValue)>MAXVALUESIZE)
		{
			memcpy(entry->m_ValueText,newValue,MAXVALUESIZE);
			entry->m_ValueText[MAXVALUESIZE] = '\0';
			CConsole::outDebOnly("CProfilingWindow: Truncated caption for value '%s' to '%s'!",key,entry->m_ValueText); 
		}
		else
		{
			strcpy(entry->m_ValueText,newValue);
		}
		entry->m_Label=NULL;

		m_pNewEntryQueue->pushBack(CStringKeyCI(key),entry);
		this->m_pValueList->pushBack(CStringKeyCI(key),entry);
	}
	else
	{
		if (entry->m_Label != NULL)
		{
			char newText[MAXVALUESIZE+1];
			if (strlen(newValue)>MAXVALUESIZE)
			{
				memcpy(entry->m_ValueText,newValue,MAXVALUESIZE);
				entry->m_ValueText[MAXVALUESIZE]=0;
			}
			else
			{
				sprintf(entry->m_ValueText,"%s",newValue);
			}
			sprintf(newText,"%s: %s",entry->m_CaptionText,entry->m_ValueText);
			SetWindowTextA( entry->m_Label, newText);
		}
	}
	RedrawWindow(m_windowHandle, NULL, NULL, RDW_INVALIDATE);
	#endif
}

void CWindowClass::setWindowName(char* newName)
{
	#ifdef WIN32
	SetWindowTextA(m_windowHandle, newName);
	#endif
}

LRESULT CALLBACK CWindowClass::callbackProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	#ifdef WIN32
	//int wmId, wmEvent;
	//PAINTSTRUCT ps;
	//HDC hdc;

	switch (message)
	{
	case WM_COMMAND:
		return DefWindowProc(hWnd, message, wParam, lParam);
		break;
	case WM_PAINT:
		//hdc = BeginPaint(hWnd, &ps);
		//EndPaint(hWnd, &ps);
		return DefWindowProc(hWnd, message, wParam, lParam);
		break;
	case WM_MOVE:
		break;
	case WM_DESTROY:
		//PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	#endif
	return 0;
}

void CWindowClass::setVisible(bool newValue)
{
	#ifdef WIN32
	ShowWindow(m_windowHandle, newValue ? SW_SHOW : SW_HIDE);
	#endif
}

void CWindowClass::toggleVisible()
{
	#ifdef WIN32
	m_visible = !m_visible;
	setVisible(m_visible);
	#endif
}

HWND CWindowClass::getWindowHandle()
{
	return m_windowHandle;
}

void CWindowClass::setWindowHandle(HWND newWindowHandle)
{
	m_windowHandle = newWindowHandle;
}